// Copyright (c) Microsoft
// All rights reserved
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.

/// <summary>Copy from Array to Array</summary>
// RUN: %amp_device -D__GPU__ %s -m32 -emit-llvm -c -S -O3 -o %t.ll && mkdir -p %t
// RUN: %llc -march=c -o %t/kernel_.cl < %t.ll
// RUN: cat %opencl_math_dir/opencl_math.cl %t/kernel_.cl > %t/kernel.cl
// RUN: pushd %t && objcopy -B i386:x86-64 -I binary -O elf64-x86-64 kernel.cl %t/kernel.o && popd
// RUN: %cxxamp %link %t/kernel.o %s -o %t.out && %t.out
#include <amp.h>
#include "../../CopyTestFlow.h"
const int RANK = 3;
using namespace Concurrency;

class ArrayToArrayTests
{
private:
	accelerator cpu_acc;
	accelerator gpu_acc;
	
	access_list access_types_vec;	

public:
	ArrayToArrayTests()
	{
		cpu_acc = accelerator(accelerator::cpu_accelerator);
		gpu_acc = require_device_for<DATA_TYPE>();
		
		compute_access_type_list(access_types_vec, gpu_acc, access_type_read_write);
	}

	int CpuAccViewToCpuAccView()
	{
		accelerator_view cpu_av = cpu_acc.get_default_view();
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(cpu_av, cpu_av, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}

	int GpuAccViewToGpuAccView()
	{
		accelerator_view gpu_av = gpu_acc.get_default_view();	
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(gpu_av, gpu_av, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}

	int CpuAccView1ToCpuAccView2()
	{
		accelerator_view cpu_av1 = cpu_acc.create_view();
		accelerator_view cpu_av2 = cpu_acc.create_view();
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(cpu_av1, cpu_av2, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}

	int GpuAccView1ToGpuAccView2()
	{
		accelerator_view gpu_av1 = gpu_acc.create_view();
		accelerator_view gpu_av2 = gpu_acc.create_view();
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(gpu_av1, gpu_av2, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}

	int CpuAccViewToGpuAccView()
	{
		accelerator_view cpu_av = cpu_acc.get_default_view();
		accelerator_view gpu_av = gpu_acc.get_default_view();
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(cpu_av, gpu_av, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}

	int GpuAccViewToCpuAccView()
	{
		accelerator_view cpu_av = cpu_acc.get_default_view();
		accelerator_view gpu_av = gpu_acc.get_default_view();
		
		int res;
		
		for(auto a_t_tuple : access_types_vec)
		{
            //print_access_type_tuple(a_t_tuple);
			res &= CopyAndVerifyFromArrayToArray<DATA_TYPE, RANK>(cpu_av, gpu_av, std::get<0>(a_t_tuple), std::get<1>(a_t_tuple), std::get<0>(a_t_tuple));
		}
		
		return res;
	}
};

int main()
{
	ArrayToArrayTests tests;
	int res = 1;

	res &= tests.CpuAccViewToCpuAccView();
	res &= tests.GpuAccViewToGpuAccView();
	res &= tests.CpuAccView1ToCpuAccView2();
	res &= tests.GpuAccView1ToGpuAccView2();
	res &= tests.CpuAccViewToGpuAccView();
	res &= tests.GpuAccViewToCpuAccView();

	return !res;
}

